import {defineStore, acceptHMRUpdate} from 'pinia';
import type { Map as MapboxMap, MapMouseEvent } from 'mapbox-gl';

export enum MapTool {
    measure = 'measure',
    weatherRect = 'weatherRect',
    drawPolygon = 'drawPolygon',
    regionFromInput = 'regionFromInput',
    pointDecoder = 'pointDecoder',
    attitudeDecoder = 'attitudeDecoder',
    climaticDecoder = 'climaticDecoder',
    /** 路线点（起/终/途径）的地图点选 */
    pointPick = 'pointPick',
    /** 任务区域左上角点选 */
    regionLTPick = 'regionLTPick',
    /** 任务区域右下角点选 */
    regionRBPick = 'regionRBPick',
    /** 自定义航线绘制 */
    diyRouteDraw = 'diyRouteDraw',
}

export interface ToolHandlers {
    start: () => void | Promise<void>;
    stop: () => void | Promise<void>;
    /** 可返回 string 作为禁用原因 */
    disabled?: () => boolean | string;
    title?: string;
}

type Registry = Partial<Record<MapTool, ToolHandlers>>;

// --- 全局 Click 监听注册表（仅针对 map-event 管理的鼠标点击类工具）---
// 目的：确保“同一时间仅存在一个由 map-event 管理的 click 监听”。
// 注意：只有通过本文件工厂函数创建、并使用 _addMapClick/_removeMapClick 的工具会被纳入管控。

type ClickListener = { map: MapboxMap; fn: (e: MapMouseEvent) => void };
const _clickListeners: ClickListener[] = [];

function _addMapClick(map: MapboxMap, fn: (e: MapMouseEvent) => void) {
    _clickListeners.push({ map, fn });
    map.on('click', fn);
}
function _removeMapClick(map: MapboxMap, fn: (e: MapMouseEvent) => void) {
    const idx = _clickListeners.findIndex(v => v.map === map && v.fn === fn);
    if (idx !== -1) _clickListeners.splice(idx, 1);
    map.off('click', fn);
}
/**
 * 移除所有由 map-event 管理（通过 _addMapClick 注册）的 click 监听。
 * 若传入 map，则仅移除该 map 上的监听。
 */
function _removeAllMapClicks(map?: MapboxMap) {
    for (let i = _clickListeners.length - 1; i >= 0; i--) {
        const { map: m, fn } = _clickListeners[i];
        if (!map || m === map) {
            try { m.off('click', fn); } catch {}
            _clickListeners.splice(i, 1);
        }
    }
}

// --- 通用鼠标事件注册表（click / mousedown / mousemove / mouseup / dblclick / contextmenu）---
// 统一记录所有通过 map-event 挂载的鼠标事件，确保工具互斥时可以“一键清空”。

type MapEvtType = 'click' | 'mousedown' | 'mousemove' | 'mouseup' | 'dblclick' | 'contextmenu';

type EvtListener = { map: MapboxMap; type: MapEvtType; fn: (e: any) => void, tool?: MapTool | null, orig?: (e: any) => void };
const _evtListeners: EvtListener[] = [];

// 当前正在 start 的工具（用于把监听与工具建立绑定关系）
let _registeringTool: MapTool | null = null;

function _addMapEvt(map: MapboxMap, type: MapEvtType, fn: (e: any) => void) {
    // 若当前处于 start(tool) 阶段，为监听打上 tool 标签并加“主动防抖”：
    // 即使意外残留监听存在，也只允许当前 activeTool 的监听生效。
    let wrapped = fn;
    if (_registeringTool) {
        const tool = _registeringTool;
        wrapped = (e: any) => {
            try {
                const store = useMapEventStore();
                if (store.activeTool !== tool) return; // 非当前激活工具，直接忽略
            } catch {}
            fn(e);
        };
        _evtListeners.push({ map, type, fn: wrapped, tool, /* 记录原始函数，便于精确卸载 */ orig: fn as any });
    } else {
        _evtListeners.push({ map, type, fn: wrapped, tool: null, orig: fn as any });
    }
    map.on(type as any, wrapped as any);
}
function _removeMapEvt(map: MapboxMap, type: MapEvtType, fn: (e: any) => void) {
    const idx = _evtListeners.findIndex(v => v.map === map && v.type === type && (v.fn === fn || (v as any).orig === fn));
    if (idx !== -1) {
        const rec = _evtListeners[idx];
        try { rec.map.off(type as any, rec.fn as any); } catch {}
        _evtListeners.splice(idx, 1);
        return;
    }
    // 兜底：直接尝试卸载传入的函数（若无包装的情况）
    try { map.off(type as any, fn as any); } catch {}
}
function _removeAllMapEvts(map?: MapboxMap) {
    for (let i = _evtListeners.length - 1; i >= 0; i--) {
        const { map: m, type, fn } = _evtListeners[i];
        if (!map || m === map) {
            try { m.off(type as any, fn as any); } catch {}
            _evtListeners.splice(i, 1);
        }
    }
}

function _removeEvtsByTool(tool: MapTool, map?: MapboxMap) {
    for (let i = _evtListeners.length - 1; i >= 0; i--) {
        const { map: m, type, fn, tool: t } = _evtListeners[i];
        if (t === tool && (!map || m === map)) {
            try { m.off(type as any, fn as any); } catch {}
            _evtListeners.splice(i, 1);
        }
    }
}

// 兼容旧 API：将 click 的注册/清理委托到通用事件注册表
(function patchClickHelpers(){
    const _oldAdd = _addMapClick;
    const _oldRemove = _removeMapClick;
    const _oldRemoveAll = _removeAllMapClicks;
    // 重写：统一走通用事件注册表
    // @ts-ignore
    _addMapClick = function(map: MapboxMap, fn: (e: MapMouseEvent) => void) {
        _addMapEvt(map, 'click', fn);
    } as any;
    // @ts-ignore
    _removeMapClick = function(map: MapboxMap, fn: (e: MapMouseEvent) => void) {
        _removeMapEvt(map, 'click', fn);
    } as any;
    // @ts-ignore
    _removeAllMapClicks = function(map?: MapboxMap) {
        _removeAllMapEvts(map); // 清空所有受管事件，命名兼容
    } as any;
})();

/** 规范化经纬度：经度归一到 [-180,180]，纬度与经度统一到 6 位小数 */
function normalizeLon(lon: number): number {
    // ((lon + 180) % 360 + 360) % 360 - 180  可将任意经度归一到 [-180, 180)
    const v = ((lon + 180) % 360 + 360) % 360 - 180;
    return +v.toFixed(6);
}
function normalizeLat(lat: number): number {
    return +lat.toFixed(6);
}

/** —— 1) 路线点点选：起/终/途径 —— */
export interface PointPickOptions {
    map: MapboxMap;
    /** 当前激活的行索引：-1 表示未激活；0..n-1 为路线点 */
    getActiveInputIdx: () => number;
    /** 退出时应将其设为 -1 */
    setActiveInputIdx: (idx: number) => void;
    /** 把拾取到的经纬度回填给第 idx 个路线点 */
    onPickRoutePoint: (idx: number, lng: number, lat: number) => void;
    /**
     * 可选：在进入/退出时的钩子，用于 UI 高亮/光标变化
     */
    onStart?
        : () => void | Promise<void>;
    onStop?
        : () => void | Promise<void>;
}

export function createPointPickHandlers(opts: PointPickOptions): ToolHandlers {
    let listener: ((e: MapMouseEvent) => void) | null = null;
    return {
        title: '点选·路线点',
        disabled: () => !opts.map && '地图未就绪',
        async start() {
            await opts.onStart?.();
            if (listener) return; // 幂等
            listener = (e: MapMouseEvent) => {
                const idx = opts.getActiveInputIdx();
                if (idx == null || idx < 0) return; // 组件侧未指定具体行，不处理
                const { lng, lat } = e.lngLat;
                opts.onPickRoutePoint(idx, normalizeLon(lng), normalizeLat(lat));
            };
            _addMapEvt(opts.map, 'click', listener as any);
        },
        async stop() {
            if (listener) {
                _removeMapEvt(opts.map, 'click', listener as any);
                listener = null;
            }
            await opts.onStop?.();
            // 统一由 Handler 在停止时将激活索引复位，避免遗漏
            try { opts.setActiveInputIdx(-1); } catch {}
        },
    };
}

/** —— 2) 任务区域左上/右下点选 —— */
export interface RegionPickOptions {
    map: MapboxMap;
    /** 将拾取到的经纬度回填到【左上】或【右下】 */
    onPick: (lng: number, lat: number) => void;
    title?: string;
    onStart?: () => void | Promise<void>;
    onStop?: () => void | Promise<void>;
}

export function createRegionPickHandlers(opts: RegionPickOptions): ToolHandlers {
    let listener: ((e: MapMouseEvent) => void) | null = null;
    return {
        title: opts.title ?? '点选·任务区域',
        disabled: () => !opts.map && '地图未就绪',
        async start() {
            await opts.onStart?.();
            if (listener) return;
            listener = (e: MapMouseEvent) => {
                const { lng, lat } = e.lngLat;
                opts.onPick(normalizeLon(lng), normalizeLat(lat));
            };
            _addMapEvt(opts.map, 'click', listener as any);
        },
        async stop() {
            if (listener) {
                _removeMapEvt(opts.map, 'click', listener as any);
                listener = null;
            }
            await opts.onStop?.();
        },
    };
}

/** —— 3) 自定义航线绘制 ——
 *  实际绘制逻辑通常在子组件中，这里只做统一 start/stop 包装
 */
export interface DiyRouteDrawOptions {
    /** 进入绘制 */
    start: () => void | Promise<void>;
    /** 结束/取消绘制，要求清理事件、图层与临时点列 */
    stop: () => void | Promise<void>;
    disabled?: () => boolean | string;
    title?: string;
}

export function createDiyRouteDrawHandlers(opts: DiyRouteDrawOptions): ToolHandlers {
    return {
        title: opts.title ?? '绘制·自定义航线',
        disabled: opts.disabled,
        async start() { await opts.start(); },
        async stop() { await opts.stop(); },
    };
}

/** —— 4) 通用 Click 工具工厂 ——
 * 任何基于 map.click 的老功能（如：测距、气象打包等）
 * 都可以用此工厂快速接入互斥机制
 */
export interface GenericClickToolOptions {
    map: MapboxMap;
    title?: string;
    disabled?: () => boolean | string;
    onStart?: () => void | Promise<void>;
    onStop?: () => void | Promise<void>;
    onClick: (e: MapMouseEvent) => void;
}
export function createClickToolHandlers(opts: GenericClickToolOptions): ToolHandlers {
    let listener: ((e: MapMouseEvent) => void) | null = null;
    return {
        title: opts.title ?? 'Click 工具',
        disabled: opts.disabled,
        async start() {
            await opts.onStart?.();
            if (listener) return;
            listener = (e: MapMouseEvent) => opts.onClick(e);
            _addMapClick(opts.map, listener);
        },
        async stop() {
            if (listener) {
                _removeMapClick(opts.map, listener);
                listener = null;
            }
            await opts.onStop?.();
        },
    };
}

/** —— 5) 测距工厂包装 ——
 * 使用示例：
 * mapEvent.registerTool(MapTool.measure, createMeasureHandlers({ map, onClick: (e) => measure.click(e), ... }))
 */
export interface MeasureHandlersOptions extends Omit<GenericClickToolOptions, 'title'> {}
export function createMeasureHandlers(opts: MeasureHandlersOptions): ToolHandlers {
    return createClickToolHandlers({ ...opts, title: '测距' });
}

/** —— 6) 气象打包（矩形/拉框）工厂包装 —— */
export interface WeatherRectHandlersOptions extends Omit<GenericClickToolOptions, 'title'> {}
export function createWeatherRectHandlers(opts: WeatherRectHandlersOptions): ToolHandlers {
    return createClickToolHandlers({ ...opts, title: '气象打包' });
}

/** —— 7) 拖拽型工具工厂（可选）——
 * 提供 mousedown / mousemove / mouseup 的统一接入，全部纳入互斥清理
 */
export interface DragToolOptions {
    map: MapboxMap;
    title?: string;
    disabled?: () => boolean | string;
    onStart?: () => void | Promise<void>;
    onStop?: () => void | Promise<void>;
    onDown?: (e: any) => void;
    onMove?: (e: any) => void;
    onUp?: (e: any) => void;
    onClick?: (e: any) => void; // 可选：需要时也能监听 click
    onDblClick?: (e: any) => void; // 可选：需要时也能监听 click
}
export function createDragToolHandlers(opts: DragToolOptions): ToolHandlers {
    const downs: ((e: any) => void)[] = [];
    const moves: ((e: any) => void)[] = [];
    const ups: ((e: any) => void)[] = [];
    const clicks: ((e: any) => void)[] = [];
    return {
        title: opts.title ?? 'Drag 工具',
        disabled: opts.disabled,
        async start() {
            await opts.onStart?.();
            if (opts.onDown) { const fn = (e: any) => opts.onDown!(e); downs.push(fn); _addMapEvt(opts.map, 'mousedown', fn); }
            if (opts.onMove) { const fn = (e: any) => opts.onMove!(e); moves.push(fn); _addMapEvt(opts.map, 'mousemove', fn); }
            if (opts.onUp)   { const fn = (e: any) => opts.onUp!(e);   ups.push(fn);   _addMapEvt(opts.map, 'mouseup', fn); }
            if (opts.onClick){ const fn = (e: any) => opts.onClick!(e); clicks.push(fn); _addMapEvt(opts.map, 'click', fn); }
        },
        async stop() {
            downs.forEach(fn => _removeMapEvt(opts.map, 'mousedown', fn));
            moves.forEach(fn => _removeMapEvt(opts.map, 'mousemove', fn));
            ups.forEach(fn => _removeMapEvt(opts.map, 'mouseup', fn));
            clicks.forEach(fn => _removeMapEvt(opts.map, 'click', fn));
            downs.length = moves.length = ups.length = clicks.length = 0;
            await opts.onStop?.();
        },
    };
}

let chain: Promise<any> = Promise.resolve();

export const useMapEventStore = defineStore('map-event', {
    state: () => ({
        activeTool: null as MapTool | null,
        registry: {} as Registry,
        /** 可选：记录最近一次错误/禁用原因，便于 UI 提示 */
        lastReason: null as string | null,
    }),
    getters: {
        isActive: (state) => (tool: MapTool) => state.activeTool === tool,
        activeTitle: (state) => (state.activeTool ? state.registry[state.activeTool]?.title ?? String(state.activeTool) : ''),
        /** 返回 boolean：是否禁用；以及可选原因 */
        disabledReason: (state) => (tool: MapTool) => {
            const d = state.registry[tool]?.disabled?.();
            return typeof d === 'string' ? d : (d ? '该工具当前不可用' : null);
        },
        isDisabled() {
            return (tool: MapTool) => !!this.disabledReason(tool);
        },
    },
    actions: {
        /** --- 简易串行队列，保证所有操作顺序执行 --- */
        async _runExclusive<T>(fn: () => Promise<T>): Promise<T> {
            // 兜底：确保chain 始终是 Promise
            const cur = (chain && typeof (chain as any).then === 'function')
                ? chain
                : Promise.resolve();

            const task = cur.then(fn, fn);
            chain = task.catch(() => {
            }); // 保持链条不断
            return task;
        },

        registerTool(tool: MapTool, handlers: ToolHandlers) {
            const wasActive = this.activeTool === tool;
            const prev = this.registry[tool];

            // 如果该工具当前处于激活状态，必须先调用“旧 handlers”的 stop，
            // 否则会遗留旧闭包中的事件监听，造成多重触发。
            if (wasActive && prev) {
                this._runExclusive(async () => {
                    try { await prev.stop?.(); } catch {}
                    // 清空所有受管鼠标事件，避免残留
                    _removeAllMapClicks();
                    _removeAllMapEvts();
                });
            }

            // 替换为新 handlers
            this.registry[tool] = handlers;

            // 若该工具本就处于激活，则用“新 handlers”重新 start 一次
            if (wasActive) {
                this._runExclusive(async () => {
                    try {
                        _registeringTool = tool;
                        await handlers.start?.();
                    } finally {
                        _registeringTool = null;
                    }
                });
            }
        },

        /** 批量注册，便于一个模块集中挂载/卸载 */
        registerMany(entries: [MapTool, ToolHandlers][]) {
            entries.forEach(([tool, handlers]) => this.registerTool(tool, handlers));
        },

        /** 可选：路由离开时清理 */
        async unregisterTool(tool: MapTool) {
            return this._runExclusive(async () => {
                if (this.activeTool === tool) {
                    const cur = this.registry[tool];
                    try { await cur?.stop?.(); } catch {}
                    this.activeTool = null;
                }
                delete this.registry[tool];
            });
        },

        async activate(tool: MapTool): Promise<boolean> {
            return this._runExclusive<boolean>(async () => {
                this.lastReason = null;
                const next = this.registry[tool];
                if (!next) {
                    this.lastReason = `工具未注册：${tool}`; return false; }

                const reason = this.disabledReason(tool);
                if (reason) { this.lastReason = reason; return false; }

                if (this.activeTool === tool) return true;

                const prev = this.activeTool;
                const prevHandlers = prev ? this.registry[prev] : null;

                if (prev) {
                    try { await prevHandlers?.stop?.(); } catch {}
                    this.activeTool = null;
                }
                // 确保 click 类工具互斥：在启动下一工具前，清空所有由 map-event 管理的 click 监听
                _removeAllMapClicks();
                _removeAllMapEvts();

                try {
                    _registeringTool = tool;
                    await next.start?.();
                    _registeringTool = null;
                    this.activeTool = tool;
                    return true;
                } catch (e) {
                    _registeringTool = null;
                    this.activeTool = null;
                    try { await next.stop?.(); } catch {}
                    // 回滚尝试
                    if (prev && prevHandlers) {
                        try {
                            await prevHandlers.start?.();
                            this.activeTool = prev;
                        } catch {}
                    }
                    this.lastReason = (e as Error)?.message ?? 'activate failed';
                    return false;
                }
            });
        },

        async toggle(tool: MapTool): Promise<boolean> {
            if (this.activeTool === tool) {
                await this.deactivate(tool);  // 这俩本身会序列化
                return false;
            }
            return await this.activate(tool);
        },

        async deactivate(tool: MapTool) {
            return this._runExclusive<void>(async () => {
                if (this.activeTool !== tool) return;
                const cur = this.registry[tool];
                try {
                    await cur?.stop?.();
                    // 保险起见，移除所有由 map-event 管理的 click 监听
                    _removeEvtsByTool(tool);
                    _removeAllMapClicks();
                    _removeAllMapEvts();
                } finally {
                    this.activeTool = null;
                }
            });
        },

        async deactivateAll() {
            return this._runExclusive<void>(async () => {
                if (!this.activeTool) return;
                const cur = this.registry[this.activeTool];
                try {
                    await cur?.stop?.();
                    if (this.activeTool) _removeEvtsByTool(this.activeTool);
                    // 保险起见，移除所有由 map-event 管理的 click 监听
                    _removeAllMapClicks();
                    _removeAllMapEvts();
                } finally {
                    this.activeTool = null;
                }
            });
        },
    },
});

// --- HMR 友好 ---
if (import.meta.hot) {
    import.meta.hot.accept(acceptHMRUpdate(useMapEventStore, import.meta.hot));
}

/** —— 8) 手动画多边形工厂 ——
 * - click 增点，dblclick 完成；
 * - 自动禁用/恢复 doubleClickZoom；
 */
export interface DrawPolygonHandlersOptions {
    map: MapboxMap;
    title?: string;
    disabled?: () => boolean | string;
    onStart?: () => void | Promise<void>;
    onStop?: () => void | Promise<void>;
    onClick: (e: any) => void;
    onDblClick: (e: any) => void;
}
export function createDrawPolygonHandlers(opts: DrawPolygonHandlersOptions): ToolHandlers {
    const startWrap = async () => {
        await opts.onStart?.();
        // 关闭双击缩放，避免 dblclick 触发地图默认行为
        try { (opts.map as any).doubleClickZoom?.disable?.(); } catch {}
    };
    const stopWrap = async () => {
        try { (opts.map as any).doubleClickZoom?.enable?.(); } catch {}
        await opts.onStop?.();
    };
    return createDragToolHandlers({
        map: opts.map,
        title: opts.title ?? '新增区域(手动)',
        disabled: opts.disabled,
        onStart: startWrap,
        onStop: stopWrap,
        onClick: opts.onClick,
        onDblClick: opts.onDblClick,
    });
}
